package com.htsk.city.services.core.utils;

import javax.servlet.http.HttpServletRequest;
import java.net.InetAddress;
import java.net.UnknownHostException;

/**
 * IP地址工具类
 */
public class IpUtils {

    private static final String UNKNOWN = "unknown";
    private static final String LOCALHOST_IPV4 = "127.0.0.1";
    private static final String LOCALHOST_IPV6 = "0:0:0:0:0:0:0:1";
    private static final String SEPARATOR = ",";

    /**
     * 获取客户端真实IP地址
     *
     * @param request HttpServletRequest对象
     * @return 真实IP地址
     */
    public static String getClientIp(HttpServletRequest request) {
        if (request == null) {
            return UNKNOWN;
        }

        String ip = request.getHeader("X-Forwarded-For");
        if (isValidIp(ip)) {
            // 多次反向代理后会有多个IP值，第一个为真实IP
            return ip.split(SEPARATOR)[0].trim();
        }

        ip = request.getHeader("X-Real-IP");
        if (isValidIp(ip)) {
            return ip;
        }

        ip = request.getHeader("Proxy-Client-IP");
        if (isValidIp(ip)) {
            return ip;
        }

        ip = request.getHeader("WL-Proxy-Client-IP");
        if (isValidIp(ip)) {
            return ip;
        }

        ip = request.getHeader("HTTP_CLIENT_IP");
        if (isValidIp(ip)) {
            return ip;
        }

        ip = request.getHeader("HTTP_X_FORWARDED_FOR");
        if (isValidIp(ip)) {
            return ip;
        }

        ip = request.getRemoteAddr();
        if (LOCALHOST_IPV6.equals(ip)) {
            ip = LOCALHOST_IPV4;
        }

        return ip;
    }

    /**
     * 验证IP地址是否有效
     *
     * @param ip IP地址
     * @return 是否有效
     */
    private static boolean isValidIp(String ip) {
        return ip != null
                && ip.length() != 0
                && !UNKNOWN.equalsIgnoreCase(ip);
    }

    /**
     * 判断是否为内网IP
     *
     * @param ip IP地址
     * @return 是否为内网IP
     */
    public static boolean isInternalIp(String ip) {
        if (ip == null || ip.length() == 0) {
            return true;
        }

        try {
            InetAddress inetAddress = InetAddress.getByName(ip);
            return inetAddress.isSiteLocalAddress()
                    || inetAddress.isLoopbackAddress()
                    || ip.startsWith("10.")
                    || ip.startsWith("192.168.")
                    || (ip.startsWith("172.") && isInRange(ip, "172.16.0.0", "172.31.255.255"));
        } catch (UnknownHostException e) {
            return true;
        }
    }

    /**
     * 判断IP是否在指定范围内
     *
     * @param ip   要判断的IP
     * @param start 起始IP
     * @param end   结束IP
     * @return 是否在范围内
     */
    private static boolean isInRange(String ip, String start, String end) {
        try {
            long ipLong = ipToLong(ip);
            long startLong = ipToLong(start);
            long endLong = ipToLong(end);
            return ipLong >= startLong && ipLong <= endLong;
        } catch (Exception e) {
            return false;
        }
    }

    /**
     * 将IP地址转换为long型数字
     *
     * @param ip IP地址
     * @return long型数字
     */
    private static long ipToLong(String ip) {
        String[] segments = ip.split("\\.");
        long result = 0;
        for (int i = 0; i < 4; i++) {
            result += Long.parseLong(segments[i]) << (24 - 8 * i);
        }
        return result;
    }

    /**
     * 获取客户端真实IP地址（包含内网IP判断）
     *
     * @param request HttpServletRequest对象
     * @return 真实IP地址，如果是内网IP则返回unknown
     */
    public static String getClientRealIp(HttpServletRequest request) {
        String ip = getClientIp(request);
        return isInternalIp(ip) ? UNKNOWN : ip;
    }

    /**
     * 获取服务器IP地址
     *
     * @return 服务器IP地址
     */
    public static String getServerIp() {
        try {
            return InetAddress.getLocalHost().getHostAddress();
        } catch (UnknownHostException e) {
            return LOCALHOST_IPV4;
        }
    }
    public static boolean isUnknown(String ip) {
        return UNKNOWN.equals(ip);
    }
}